
#include "../../inc/skyPict.h"
#ifdef _GLES_


#include "../windows/winImage.h"
#undef _STRSAFE_H_INCLUDED_
#include "../thirdParty/Tools/PVRTools.h"

namespace Sky
{

    Bool PictManager::createPictFromFile( String* filePath,Pict* pict,Callback doneCallback )
    {
#ifdef _AND_
		Java_Invoke_LoadFile(filePath->toCharString(),JByte* buff);
		createPictFromRawBuffer(Buffer,pict,doneCallback);
#elif defined(_IOS_)
		CGImageRef textureImage = [UIImage imageNamed:filePath->toCharString()].CGImage;
		NSInteger texWidth = CGImageGetWidth(textureImage);
		NSInteger texHeight = CGImageGetHeight(textureImage);
		GLubyte *textureData = (GLubyte *)malloc(texWidth * texHeight * 4);
		CGContextRef textureContext = CGBitmapContextCreate(
			textureData,
			texWidth,
			texHeight,
			8, texWidth * 4,
			CGImageGetColorSpace(textureImage),
			kCGImageAlphaPremultipliedLast);

		CGContextDrawImage(textureContext,CGRectMake(0.0, 0.0, (float)texWidth, (float)texHeight),textureImage);

		CGContextRelease(textureContext);
		createPictFromBuffer(Buffer,pict,doneCallback);
		free(textureData);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#else
		/*do 
		{
			Image img;
			E_Break_If(vFalse == img.createWithImageFile(filePath,Image::FmtJpg));
			pict->_size.w = img.getWidth();
			pict->_size.h = img.getHeight();
			pict->_hasAlpha = img.hasAlpha();
			pict->_bitsPerComponent = img.getBitsPerComponent();
			return createPictFromBuffer(&Buffer(img.getData(),img.getDataLen()),pict);
		} while (0);*/
		PVR_Texture_Header head;
		if(PVRTTextureLoadFromPVR(filePath->toCharString(), &pict->_tex,&head) != PVR_SUCCESS)
		{
			xError1A("%s failed",filePath->toCharString());
			xAssert(0);
			return vFalse;
		}
		pict->_size.w = head.dwWidth;
		pict->_size.h = head.dwHeight;
		
#endif
        return vTrue;
    }
	unsigned long ccNextPOT(unsigned long x)
	{
		x = x - 1;
		x = x | (x >> 1);
		x = x | (x >> 2);
		x = x | (x >> 4);
		x = x | (x >> 8);
		x = x | (x >>16);
		return x + 1;
	}

    Bool PictManager::createPictFromBuffer(Buffer* buffer,Pict* pict,Callback doneCallback)
    {
		pict->_tex = 0;
		glPixelStorei(GL_UNPACK_ALIGNMENT,1);				// Never have row-aligned in psPVRHeaders
		glGenTextures(1, &pict->_tex);

		glBindTexture(GL_TEXTURE_2D, pict->_tex);

		//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 

		u32 w = pict->getSize().w;
		u32 h = pict->getSize().h;

		GLsizei pixelsWide = ccNextPOT(w);
		GLsizei pixelsHigh = ccNextPOT(h);

		//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

		if(buffer == vNull)
		{
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, vNull);
			xAssert(GL_NO_ERROR == glGetError());
			return vTrue;
		}
		u8* data = buffer ? buffer->getBuffer() : vNull;


		unsigned char*			tempData =NULL;
		unsigned int*			inPixel32 = NULL;
		unsigned short*			outPixel16 = NULL;
		Bool					hasAlpha;
		Size					imageSize;
		CCTexture2DPixelFormat	pixelFormat;
		i32 POTWide = ccNextPOT(pict->getSize().w);
		i32 POTHigh = ccNextPOT(pict->getSize().h);
		hasAlpha = pict->getHasAlpha();

		size_t bpp = pict->getBitsPerComponent();

		// compute pixel format
		if(hasAlpha)
		{
			pixelFormat = kCCTexture2DPixelFormat_Default;
		}
		else
		{
			if (bpp >= 8)
			{
				pixelFormat = kCCTexture2DPixelFormat_RGB888;
			}
			else
			{
				pixelFormat = kCCTexture2DPixelFormat_RGB565;
			}
		}


		imageSize = Size((pict->getSize().w), (pict->getSize().h));

		switch(pixelFormat) {    
			case kCCTexture2DPixelFormat_RGBA8888:
			case kCCTexture2DPixelFormat_RGBA4444:
			case kCCTexture2DPixelFormat_RGB5A1:
			case kCCTexture2DPixelFormat_RGB565:
			case kCCTexture2DPixelFormat_A8:
				tempData = (unsigned char*)(buffer->getBuffer());
				xAssertA(tempData != NULL);

				if(pict->getSize().w == (short)POTWide && pict->getSize().h == (short)POTHigh)
				{
					data = new unsigned char[POTHigh * POTWide * 4];
					memcpy(data, tempData, POTHigh * POTWide * 4);
				}
				else
				{
					data = new unsigned char[POTHigh * POTWide * 4];
					memset(data, 0, POTHigh * POTWide * 4);

					unsigned char* pPixelData = (unsigned char*) tempData;
					unsigned char* pTargetData = (unsigned char*) data;

					int imageHeight = pict->getSize().h;
					for(int y = 0; y < imageHeight; ++y)
					{
						memcpy(pTargetData+POTWide*4*(imageHeight-y), pPixelData+(pict->getSize().w)*4*y, (pict->getSize().w)*4);
					}
				}

				break;    
			case kCCTexture2DPixelFormat_RGB888:
				tempData = (unsigned char*)(buffer->getBuffer());
				xAssertA(tempData != NULL && "NULL image data.");
				if(pict->getSize().w == (short)POTWide && pict->getSize().h == (short)POTHigh)
				{
					data = new unsigned char[POTHigh * POTWide * 3];
					memcpy(data, tempData, POTHigh * POTWide * 3);
				}
				else
				{
					data = new unsigned char[POTHigh * POTWide * 3];
					memset(data, 0, POTHigh * POTWide * 3);

					unsigned char* pPixelData = (unsigned char*) tempData;
					unsigned char* pTargetData = (unsigned char*) data;

					int imageHeight = pict->getSize().h;
					for(int y = 0; y < imageHeight; ++y)
					{
						memcpy(pTargetData+POTWide*3*y, pPixelData+(pict->getSize().w)*3*y, (pict->getSize().w)*3);
					}
				}
				break;   
			default:
				xAssertA(0 && "Invalid pixel format");
		}

		// Repack the pixel data into the right format

		if(pixelFormat == kCCTexture2DPixelFormat_RGB565) {

			tempData = new unsigned char[POTHigh * POTWide * 2];
			inPixel32 = (unsigned int*)data;
			outPixel16 = (unsigned short*)tempData;

			unsigned int length = POTWide * POTHigh;
			for(unsigned int i = 0; i < length; ++i, ++inPixel32)
			{
				*outPixel16++ = 
					((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) |  // R
					((((*inPixel32 >> 8) & 0xFF) >> 2) << 5) |   // G
					((((*inPixel32 >> 16) & 0xFF) >> 3) << 0);   // B
			}

			delete [] data;
			data = tempData;
		}
		else if (pixelFormat == kCCTexture2DPixelFormat_RGBA4444) {

			tempData = new unsigned char[POTHigh * POTWide * 2];
			inPixel32 = (unsigned int*)data;
			outPixel16 = (unsigned short*)tempData;

			unsigned int length = POTWide * POTHigh;
			for(unsigned int i = 0; i < length; ++i, ++inPixel32)
			{
				*outPixel16++ = 
				((((*inPixel32 >> 0) & 0xFF) >> 4) << 12) | // R
				((((*inPixel32 >> 8) & 0xFF) >> 4) << 8) | // G
				((((*inPixel32 >> 16) & 0xFF) >> 4) << 4) | // B
				((((*inPixel32 >> 24) & 0xFF) >> 4) << 0); // A
			}

			delete [] data;
			data = tempData;
		}
		else if (pixelFormat == kCCTexture2DPixelFormat_RGB5A1) {

			tempData = new unsigned char[POTHigh * POTWide * 2];
			inPixel32 = (unsigned int*)data;
			outPixel16 = (unsigned short*)tempData;

			unsigned int length = POTWide * POTHigh;
			for(unsigned int i = 0; i < length; ++i, ++inPixel32)
			{
				*outPixel16++ = 
				((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R
				((((*inPixel32 >> 8) & 0xFF) >> 3) << 6) | // G
				((((*inPixel32 >> 16) & 0xFF) >> 3) << 1) | // B
				((((*inPixel32 >> 24) & 0xFF) >> 7) << 0); // A
			}

			delete []data;
			data = tempData;
		}
		else if (pixelFormat == kCCTexture2DPixelFormat_A8)
		{
			// fix me, how to convert to A8
			pixelFormat = kCCTexture2DPixelFormat_RGBA8888;

			/*
			 * The code can not work, how to convert to A8?
			 *
			tempData = new unsigned char[POTHigh * POTWide];
			inPixel32 = (unsigned int*)data;
			outPixel8 = tempData;

			unsigned int length = POTWide * POTHigh;
			for(unsigned int i = 0; i < length; ++i, ++inPixel32)
			{
				*outPixel8++ = (*inPixel32 >> 24) & 0xFF;
			}

			delete []data;
			data = tempData;
			*/
		}
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

		if (data)
		{
			switch(pixelFormat)
			{
			case kCCTexture2DPixelFormat_RGBA8888:
				glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
				break;
			case kCCTexture2DPixelFormat_RGB888:
				glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
				break;
			case kCCTexture2DPixelFormat_RGBA4444:
				glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
				break;
			case kCCTexture2DPixelFormat_RGB5A1:
				glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, data);
				break;
			case kCCTexture2DPixelFormat_RGB565:
				glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
				break;
			case kCCTexture2DPixelFormat_I8:
				glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data);
				break;
			case kCCTexture2DPixelFormat_A8:
				glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data);
				break;
			default:
				xAssert(0&& "NSInternalInconsistencyException");

			}
			delete [] data;
		}
        return vTrue;
    }


	Bool Sky::PictManager::createPictFromRawBuffer( Buffer* buffer,Pict* pict,Callback doneCallback /*= vNull*/ )
	{
		return vTrue;
	}



	Size Pict::getSize()
	{
		return  _size;
	}


	GLint OSPict::getTexture()
	{
		return _tex;
	}

	Size OSPict::setDesiredSize( Size size )
	{
		_size = size;
		return _size;
	}

}
#endif
